package com.gitee.wsl.android.ui.ext.type

import android.graphics.*
import android.graphics.drawable.ShapeDrawable
import android.graphics.drawable.shapes.PathShape

import androidx.graphics.shapes.Morph

import com.gitee.wsl.android.ext.math.dp
import kotlin.math.abs
import kotlin.math.cos
import kotlin.math.min
import kotlin.math.sin


object PathExt {

    fun resizePath(path: Path, width: Float, height: Float) {
        val bounds = RectF(0f, 0f, width, height)
        val src = RectF()
        path.computeBounds(src, true)
        val resizeMatrix = Matrix()
        resizeMatrix.setRectToRect(src, bounds, Matrix.ScaleToFit.FILL)
        path.transform(resizeMatrix)
    }

    fun setPathWidth(path: Path, width: Float) {
        val src = RectF()
        path.computeBounds(src, true)
        val resizeMatrix = Matrix()
        val bounds = RectF(src.left, src.top, src.left + width, src.bottom)
        resizeMatrix.setRectToRect(src, bounds, Matrix.ScaleToFit.FILL)
        path.transform(resizeMatrix)
    }

    fun setPathHeight(path: Path, height: Float) {
        val src = RectF()
        path.computeBounds(src, true)
        val resizeMatrix = Matrix()
        val bounds = RectF(src.left, src.top, src.right, src.top + height)
        resizeMatrix.setRectToRect(src, bounds, Matrix.ScaleToFit.FILL)
        path.transform(resizeMatrix)
    }


    fun getPathWidth(path: Path): Float {
        val rect = RectF()
        path.computeBounds(rect, true)
        return rect.width()
    }

    fun getPathHeight(path: Path): Float {
        val rect = RectF()
        path.computeBounds(rect, true)
        return rect.height()
    }

    fun setPathRotation(path: Path, rotation: Float) {
        val rect = RectF()
        path.computeBounds(rect, true)
        setPathRotation(path, rotation, rect.centerX(), rect.centerY())
    }

    fun setPathRotation(path: Path, rotation: Float, px: Float, py: Float) {
        val matrix = Matrix()
        matrix.setRotate(rotation, px, py)
        path.transform(matrix)
    }

    fun setPathTranslationX(path: Path, translationX: Float) {
        val matrix = Matrix()
        matrix.postTranslate(translationX, 0f)
        path.transform(matrix)
    }

    fun setPathTranslationY(path: Path, translationY: Float) {
        val matrix = Matrix()
        matrix.setTranslate(0f, translationY)
        path.transform(matrix)
    }


    fun setPathScaleX(path: Path, scale: Float, px: Float, py: Float) {
        val matrix = Matrix()
        matrix.setScale(scale, 1f, px, py)
        path.transform(matrix)
    }

    fun setPathScaleY(path: Path, scale: Float, px: Float, py: Float) {
        val matrix = Matrix()
        matrix.setScale(1f, scale, px, py)
        path.transform(matrix)
    }

    fun setPathScaleX(path: Path, scale: Float) {
        val rect = RectF()
        path.computeBounds(rect, true)
        setPathScaleX(path, scale, rect.centerX(), rect.centerY())
    }

    fun setPathScaleY(path: Path, scale: Float) {
        val rect = RectF()
        path.computeBounds(rect, true)
        setPathScaleY(path, scale, rect.centerX(), rect.centerY())
    }

    fun isTouched(path: Path, x: Float, y: Float): Boolean {
        val region = Region()
        val rectF = RectF()
        path.computeBounds(rectF, true)
        region.setPath(
            path,
            Region(rectF.left.toInt(), rectF.top.toInt(), rectF.right.toInt(), rectF.bottom.toInt())
        )
        val offset = 10
        return (region.contains(x.toInt(), y.toInt())
                || region.contains(x.toInt() + offset, y.toInt() + offset)
                || region.contains(x.toInt() + offset, y.toInt() - offset)
                || region.contains(x.toInt() - offset, y.toInt() - offset)
                || region.contains(x.toInt() - offset, y.toInt() + offset))
    }

    //圆角
    fun generateRoundRectPath(
        useBezier: Boolean,
        rect: RectF,
        topLeftRadius: Float,
        topRightRadius: Float,
        bottomRightRadius: Float,
        bottomLeftRadius: Float
    ): Path {
        val path = Path()
        val left = rect.left
        val top = rect.top
        val bottom = rect.bottom
        val right = rect.right
        val maxSize = (rect.width() / 2f).coerceAtMost(rect.height() / 2f)
        var topLeftRadiusAbs = abs(topLeftRadius)
        var topRightRadiusAbs = abs(topRightRadius)
        var bottomLeftRadiusAbs = abs(bottomLeftRadius)
        var bottomRightRadiusAbs = abs(bottomRightRadius)
        if (topLeftRadiusAbs > maxSize) {
            topLeftRadiusAbs = maxSize
        }
        if (topRightRadiusAbs > maxSize) {
            topRightRadiusAbs = maxSize
        }
        if (bottomLeftRadiusAbs > maxSize) {
            bottomLeftRadiusAbs = maxSize
        }
        if (bottomRightRadiusAbs > maxSize) {
            bottomRightRadiusAbs = maxSize
        }
        path.moveTo(left + topLeftRadiusAbs, top)
        path.lineTo(right - topRightRadiusAbs, top)

        //float left, float top, float right, float bottom, float startAngle, float sweepAngle, boolean forceMoveTo
        if (useBezier) {
            path.quadTo(right, top, right, top + topRightRadiusAbs)
        } else {
            val arc: Float = if (topRightRadius > 0) 90f else -270f
            path.arcTo(
                RectF(
                    right - topRightRadiusAbs * 2f,
                    top,
                    right,
                    top + topRightRadiusAbs * 2f
                ), -90f, arc
            )
        }
        path.lineTo(right, bottom - bottomRightRadiusAbs)
        if (useBezier) {
            path.quadTo(right, bottom, right - bottomRightRadiusAbs, bottom)
        } else {
            val arc: Float = if (bottomRightRadiusAbs > 0) 90f else -270f
            path.arcTo(
                RectF(
                    right - bottomRightRadiusAbs * 2f,
                    bottom - bottomRightRadiusAbs * 2f,
                    right,
                    bottom
                ), 0f, arc
            )
        }
        path.lineTo(left + bottomLeftRadiusAbs, bottom)
        if (useBezier) {
            path.quadTo(left, bottom, left, bottom - bottomLeftRadiusAbs)
        } else {
            val arc: Float = if (bottomLeftRadiusAbs > 0) 90f else -270f
            path.arcTo(
                RectF(
                    left,
                    bottom - bottomLeftRadiusAbs * 2f,
                    left + bottomLeftRadiusAbs * 2f,
                    bottom
                ), 90f, arc
            )
        }
        path.lineTo(left, top + topLeftRadiusAbs)
        if (useBezier) {
            path.quadTo(left, top, left + topLeftRadiusAbs, top)
        } else {
            val arc: Float = if (topLeftRadiusAbs > 0) 90f else -270f
            path.arcTo(
                RectF(left, top, left + topLeftRadiusAbs * 2f, top + topLeftRadiusAbs * 2f),
                180f,
                arc
            )
        }
        path.close()
        return path
    }

    //多边型
    fun generatePolygonPath(width: Int, height: Int, numberOfSides: Int): Path {
        val section = 2.0 * Math.PI / numberOfSides
        val polygonSize = Math.min(width, height)
        val radius = polygonSize / 2
        val centerX = width / 2
        val centerY = height / 2
        val polygonPath = Path()
        polygonPath.moveTo(
            centerX + radius * cos(0.0).toFloat(),
            centerY + radius * sin(0.0).toFloat()
        )
        for (i in 1 until numberOfSides) {
            polygonPath.lineTo(
                centerX + radius * cos(section * i).toFloat(),
                centerY + radius * sin(section * i).toFloat()
            )
        }
        polygonPath.close()
        return polygonPath
    }

    //带锯齿
    fun generateDottedEdgesCutCornerPath(
        rect: RectF,
        topLeftDiameter1: Float,
        topRightDiameter1: Float,
        bottomRightDiameter1: Float,
        bottomLeftDiameter1: Float,
        dotEdgePosition: Position = Position.LEFT,
        dotRadius: Float = 0f,
        dotSpacing: Float = 0f
    ): Path {
        val path = Path()
        val topLeftDiameter = if (topLeftDiameter1 < 0) 0f else topLeftDiameter1
        val topRightDiameter = if (topRightDiameter1 < 0) 0f else topRightDiameter1
        val bottomLeftDiameter = if (bottomLeftDiameter1 < 0) 0f else bottomLeftDiameter1
        val bottomRightDiameter = if (bottomRightDiameter1 < 0) 0f else bottomRightDiameter1
        path.moveTo(rect.left + topLeftDiameter, rect.top)
        if (containsFlag(Position.TOP, dotEdgePosition)) {
            var count = 1
            var x = rect.left + topLeftDiameter + dotSpacing * count + dotRadius * 2 * (count - 1)
            while (x + dotSpacing + dotRadius * 2 <= rect.right - topRightDiameter) {
                x = (rect.left + topLeftDiameter + dotSpacing * count + dotRadius * 2 * (count - 1))
                path.lineTo(x, rect.top)
                path.quadTo(x + dotRadius, rect.top + dotRadius, x + dotRadius * 2, rect.top)
                count++
            }
            path.lineTo(rect.right - topRightDiameter, rect.top)
        } else {
            path.lineTo(rect.right - topRightDiameter, rect.top)
        }
        path.lineTo(rect.right, rect.top + topRightDiameter)
        if (containsFlag(Position.RIGHT, dotEdgePosition)) {
            //drawing dots starts from the bottom just like the LEFT side so that when using two
            //widgets side by side, their dots positions will match each other
            path.lineTo(rect.right - dotRadius, rect.top + topRightDiameter)
            path.lineTo(rect.right - dotRadius, rect.bottom - bottomRightDiameter)
            path.lineTo(rect.right, rect.bottom - bottomRightDiameter)
            var count = 1
            var y =
                rect.bottom - bottomRightDiameter - dotSpacing * count - dotRadius * 2 * (count - 1)
            while (y - dotSpacing - dotRadius * 2 >= rect.top + topRightDiameter) {
                y =
                    (rect.bottom - bottomRightDiameter - dotSpacing * count - dotRadius * 2 * (count - 1))
                path.lineTo(rect.right, y)
                path.quadTo(rect.right - dotRadius, y - dotRadius, rect.right, y - dotRadius * 2)
                count++
            }
            path.lineTo(rect.right, rect.top + topRightDiameter)
            path.lineTo(rect.right - dotRadius, rect.top + topRightDiameter)
            path.lineTo(rect.right - dotRadius, rect.bottom - bottomRightDiameter)
            path.lineTo(rect.right, rect.bottom - bottomRightDiameter)
        } else {
            path.lineTo(rect.right, rect.bottom - bottomRightDiameter)
        }
        path.lineTo(rect.right - bottomRightDiameter, rect.bottom)
        if (containsFlag(Position.BOTTOM, dotEdgePosition)) {
            var count = 1
            var x =
                rect.right - bottomRightDiameter - dotSpacing * count - dotRadius * 2 * (count - 1)
            while (x - dotSpacing - dotRadius * 2 >= rect.left + bottomLeftDiameter) {
                x =
                    (rect.right - bottomRightDiameter - dotSpacing * count - dotRadius * 2 * (count - 1))
                path.lineTo(x, rect.bottom)
                path.quadTo(x - dotRadius, rect.bottom - dotRadius, x - dotRadius * 2, rect.bottom)
                count++
            }
            path.lineTo(rect.left + bottomLeftDiameter, rect.bottom)
        } else {
            path.lineTo(rect.left + bottomLeftDiameter, rect.bottom)
        }
        path.lineTo(rect.left, rect.bottom - bottomLeftDiameter)
        if (containsFlag(Position.LEFT, dotEdgePosition)) {
            var count = 1
            var y =
                rect.bottom - bottomLeftDiameter - dotSpacing * count - dotRadius * 2 * (count - 1)
            while (y - dotSpacing - dotRadius * 2 >= rect.top + topLeftDiameter) {
                y =
                    (rect.bottom - bottomLeftDiameter - dotSpacing * count - dotRadius * 2 * (count - 1))
                path.lineTo(rect.left, y)
                path.quadTo(rect.left + dotRadius, y - dotRadius, rect.left, y - dotRadius * 2)
                count++
            }
            path.lineTo(rect.left, rect.top + topLeftDiameter)
        } else {
            path.lineTo(rect.left, rect.top + topLeftDiameter)
        }
        path.lineTo(rect.left + topLeftDiameter, rect.top)
        path.close()
        return path
    }

    private fun containsFlag(
        positionFlag: Position,
        dotEdgePosition: Position = Position.RIGHT
    ): Boolean {
        return positionFlag == dotEdgePosition
    }

    //切角
    fun generateCutCornerPath(
        rect: RectF,
        topLeftDiameter1: Float,
        topRightDiameter1: Float,
        bottomRightDiameter1: Float,
        bottomLeftDiameter1: Float
    ): Path {
        val path = Path()
        val topLeftDiameter = if (topLeftDiameter1 < 0) 0f else topLeftDiameter1
        val topRightDiameter = if (topRightDiameter1 < 0) 0f else topRightDiameter1
        val bottomLeftDiameter = if (bottomLeftDiameter1 < 0) 0f else bottomLeftDiameter1
        val bottomRightDiameter = if (bottomRightDiameter1 < 0) 0f else bottomRightDiameter1
        path.moveTo(rect.left + topLeftDiameter, rect.top)
        path.lineTo(rect.right - topRightDiameter, rect.top)
        path.lineTo(rect.right, rect.top + topRightDiameter)
        path.lineTo(rect.right, rect.bottom - bottomRightDiameter)
        path.lineTo(rect.right - bottomRightDiameter, rect.bottom)
        path.lineTo(rect.left + bottomLeftDiameter, rect.bottom)
        path.lineTo(rect.left, rect.bottom - bottomLeftDiameter)
        path.lineTo(rect.left, rect.top + topLeftDiameter)
        path.lineTo(rect.left + topLeftDiameter, rect.top)
        path.close()
        return path
    }

    //斜角
    fun generateDiagonalPath(
        width: Int,
        height: Int,
        paddingLeft: Float,
        paddingRight: Float,
        paddingTop: Float,
        paddingBottom: Float,
        diagonalPosition: Position = Position.BOTTOM,
        isDirectionLeft: Boolean = false,
        diagonalAngle: Float
    ): Path {
        val path = Path()
        val diagonalAngleAbs: Float = Math.abs(diagonalAngle)
        //val isDirectionLeft = getDiagonalDirection() === DIRECTION_LEFT
        val perpendicularHeight =
            (width * Math.tan(Math.toRadians(diagonalAngleAbs.toDouble()))).toFloat()
        when (diagonalPosition) {
            Position.BOTTOM -> if (isDirectionLeft) {
                path.moveTo(paddingLeft, paddingRight)
                path.lineTo(width - paddingRight, paddingTop)
                path.lineTo(
                    width - paddingRight,
                    height - perpendicularHeight - paddingBottom
                )
                path.lineTo(paddingLeft, height - paddingBottom)
                path.close()
            } else {
                path.moveTo(width - paddingRight, height - paddingBottom)
                path.lineTo(paddingLeft, height - perpendicularHeight - paddingBottom)
                path.lineTo(paddingLeft, paddingTop)
                path.lineTo(width - paddingRight, paddingTop)
                path.close()
            }

            Position.TOP -> if (isDirectionLeft) {
                path.moveTo(width - paddingRight, height - paddingBottom)
                path.lineTo(width - paddingRight, paddingTop + perpendicularHeight)
                path.lineTo(paddingLeft, paddingTop)
                path.lineTo(paddingLeft, height - paddingBottom)
                path.close()
            } else {
                path.moveTo(width - paddingRight, height - paddingBottom)
                path.lineTo(width - paddingRight, paddingTop)
                path.lineTo(paddingLeft, paddingTop + perpendicularHeight)
                path.lineTo(paddingLeft, height - paddingBottom)
                path.close()
            }

            Position.RIGHT -> if (isDirectionLeft) {
                path.moveTo(paddingLeft, paddingTop)
                path.lineTo(width - paddingRight, paddingTop)
                path.lineTo(
                    width - paddingRight - perpendicularHeight,
                    height - paddingBottom
                )
                path.lineTo(paddingLeft, height - paddingBottom)
                path.close()
            } else {
                path.moveTo(paddingLeft, paddingTop)
                path.lineTo(width - paddingRight - perpendicularHeight, paddingTop)
                path.lineTo(width - paddingRight, height - paddingBottom)
                path.lineTo(paddingLeft, height - paddingBottom)
                path.close()
            }

            Position.LEFT -> if (isDirectionLeft) {
                path.moveTo(paddingLeft + perpendicularHeight, paddingTop)
                path.lineTo(width - paddingRight, paddingTop)
                path.lineTo(width - paddingRight, height - paddingBottom)
                path.lineTo(paddingLeft, height - paddingBottom)
                path.close()
            } else {
                path.moveTo(paddingLeft, paddingTop)
                path.lineTo(width - paddingRight, paddingTop)
                path.lineTo(width - paddingRight, height - paddingBottom)
                path.lineTo(paddingLeft + perpendicularHeight, height - paddingBottom)
                path.close()
            }
        }
        return path
    }

    //星型
    fun generateStarPath(width: Int, height: Int, noOfPoints: Int = 5): Path {
        val vertices: Int = noOfPoints * 2
        val alpha = 2 * Math.PI / vertices
        val radius = min(height, width) / 2 //(if (height <= width) height else width) / 2
        val centerX = width / 2
        val centerY = height / 2
        val path = Path()
        for (i in vertices + 1 downTo 1) {
            val r = radius * (i % 2 + 1) / 2
            val omega = alpha * i
            path.lineTo(
                (r * sin(omega)).toFloat() + centerX,
                (r * cos(omega)).toFloat() + centerY
            )
        }
        path.close()
        return path
    }

    //三角(使用 V 型算法)
    fun generateTrianglePath(
        width: Float, height: Float,
        percentLeft: Float = 0f,
        percentRight: Float = 0f,
        percentBottom: Float = 0.5f
    ): Path {
        val path = Path()
        path.moveTo(0f, percentLeft * height)
        path.lineTo(percentBottom * width, height)
        path.lineTo(width, percentRight * height)
        path.close()
        return path
    }

    //弧形 isCropInside
    fun generateAcePath(
        width: Float, height: Float,
        arcHeightPx: Float,
        isCropInside: Boolean = false,
        arcPosition: Position = Position.RIGHT
    ): Path {
        val path = Path()
        //val isCropInside = getCropDirection() === CROP_INSIDE
        val arcHeightAbs: Float = abs(arcHeightPx)
        when (arcPosition) {
            Position.BOTTOM -> {
                if (isCropInside) {
                    path.moveTo(0f, 0f)
                    path.lineTo(0f, height)
                    path.quadTo(
                        width / 2,
                        height - 2 * arcHeightAbs,
                        width,
                        height
                    )
                    path.lineTo(width, 0f)
                    path.close()
                } else {
                    path.moveTo(0f, 0f)
                    path.lineTo(0f, height - arcHeightAbs)
                    path.quadTo(
                        width / 2,
                        height + arcHeightAbs,
                        width,
                        height - arcHeightAbs
                    )
                    path.lineTo(width, 0f)
                    path.close()
                }
            }

            Position.TOP -> if (isCropInside) {
                path.moveTo(0f, height)
                path.lineTo(0f, 0f)
                path.quadTo(width / 2, 2 * arcHeightAbs, width, 0f)
                path.lineTo(width, height)
                path.close()
            } else {
                path.moveTo(0f, arcHeightAbs)
                path.quadTo(width / 2, -arcHeightAbs, width, arcHeightAbs)
                path.lineTo(width, height)
                path.lineTo(0f, height)
                path.close()
            }

            Position.LEFT -> if (isCropInside) {
                path.moveTo(width, 0f)
                path.lineTo(0f, 0f)
                path.quadTo(arcHeightAbs * 2, height / 2, 0f, height)
                path.lineTo(width, height)
                path.close()
            } else {
                path.moveTo(width, 0f)
                path.lineTo(arcHeightAbs, 0f)
                path.quadTo(-arcHeightAbs, height / 2, arcHeightAbs, height)
                path.lineTo(width, height)
                path.close()
            }

            Position.RIGHT -> if (isCropInside) {
                path.moveTo(0f, 0f)
                path.lineTo(width, 0f)
                path.quadTo(
                    width - arcHeightAbs * 2,
                    height / 2,
                    width,
                    height
                )
                path.lineTo(0f, height)
                path.close()
            } else {
                path.moveTo(0f, 0f)
                path.lineTo(width - arcHeightAbs, 0f)
                path.quadTo(
                    width + arcHeightAbs,
                    height / 2,
                    width - arcHeightAbs,
                    height
                )
                path.lineTo(0f, height)
                path.close()
            }
        }
        return path
    }

    //提示框
    fun generateBubbleAcePath(
        myRect: RectF,
        borderRadiusPx: Float,
        topLeftDiameter1: Float = borderRadiusPx,
        topRightDiameter1: Float = borderRadiusPx,
        bottomRightDiameter1: Float = borderRadiusPx,
        bottomLeftDiameter1: Float = borderRadiusPx,
        bubblePosition: Position = Position.BOTTOM,
        positionPer: Float = 0.5f,
        arrowHeightPx: Float = 10f.dp,
        arrowWidthPx: Float = 10f.dp
    ): Path {
        val topLeftDiameter = if (topLeftDiameter1 < 0) 0f else topLeftDiameter1
        val topRightDiameter = if (topRightDiameter1 < 0) 0f else topRightDiameter1
        val bottomLeftDiameter = if (bottomLeftDiameter1 < 0) 0f else bottomLeftDiameter1
        val bottomRightDiameter = if (bottomRightDiameter1 < 0) 0f else bottomRightDiameter1
        val path = Path()
        val spacingLeft: Float = if (bubblePosition == Position.LEFT) arrowHeightPx else 0f
        val spacingTop: Float = if (bubblePosition == Position.TOP) arrowHeightPx else 0f
        val spacingRight: Float = if (bubblePosition == Position.RIGHT) arrowHeightPx else 0f
        val spacingBottom: Float = if (bubblePosition == Position.BOTTOM) arrowHeightPx else 0f
        val left = spacingLeft + myRect.left
        val top = spacingTop + myRect.top
        val right = myRect.right - spacingRight
        val bottom = myRect.bottom - spacingBottom
        val centerX: Float = (myRect.left + myRect.right) * positionPer
        path.moveTo(left + topLeftDiameter / 2f, top)
        //LEFT, TOP
        if (bubblePosition == Position.TOP) {
            path.lineTo(centerX - arrowWidthPx, top)
            path.lineTo(centerX, myRect.top)
            path.lineTo(centerX + arrowWidthPx, top)
        }
        path.lineTo(right - topRightDiameter / 2f, top)
        path.quadTo(right, top, right, top + topRightDiameter / 2)
        //RIGHT, TOP
        if (bubblePosition == Position.RIGHT) {
            path.lineTo(right, bottom - bottom * (1 - positionPer) - arrowWidthPx)
            path.lineTo(myRect.right, bottom - bottom * (1 - positionPer))
            path.lineTo(right, bottom - bottom * (1 - positionPer) + arrowWidthPx)
        }
        path.lineTo(right, bottom - bottomRightDiameter / 2)
        path.quadTo(right, bottom, right - bottomRightDiameter / 2, bottom)
        //RIGHT, BOTTOM
        if (bubblePosition == Position.BOTTOM) {
            path.lineTo(centerX + arrowWidthPx, bottom)
            path.lineTo(centerX, myRect.bottom)
            path.lineTo(centerX - arrowWidthPx, bottom)
        }
        path.lineTo(left + bottomLeftDiameter / 2, bottom)
        path.quadTo(left, bottom, left, bottom - bottomLeftDiameter / 2)
        //LEFT, BOTTOM
        if (bubblePosition == Position.LEFT) {
            path.lineTo(left, bottom - bottom * (1 - positionPer) + arrowWidthPx)
            path.lineTo(myRect.left, bottom - bottom * (1 - positionPer))
            path.lineTo(left, bottom - bottom * (1 - positionPer) - arrowWidthPx)
        }
        path.lineTo(left, top + topLeftDiameter / 2)
        path.quadTo(left, top, left + topLeftDiameter / 2, top)
        path.close()
        return path
    }

/**
    import org.opencv.android.Utils
    import org.opencv.core.Mat
    import org.opencv.core.MatOfPoint
    import org.opencv.core.MatOfPoint2f
    import org.opencv.core.Size
    import org.opencv.imgproc.Imgproc

    fun  getPathFromDrawable( @DrawableRes res: Int): List<Path> {
        val bgr = Utils.loadResource(App.context(), res)
        var mSource = Mat()
        Imgproc.cvtColor(bgr, mSource, Imgproc.COLOR_BGR2RGB)
        val tmp = mSource.clone()
        val gray = Mat()
        Imgproc.cvtColor(mSource, gray, Imgproc.COLOR_BGR2GRAY)
        Imgproc.GaussianBlur(gray, gray, Size(55.0, 55.0), 50.0, 50.0)
        val binary = Mat()
        Imgproc.threshold(gray, binary, 50.0, 255.0, Imgproc.THRESH_BINARY and Imgproc.THRESH_OTSU)

        val contours = mutableListOf<MatOfPoint>()
        val hierarchy = Mat()
        Imgproc.findContours(
            binary,
            contours,
            hierarchy,
            Imgproc.RETR_EXTERNAL,
            Imgproc.CHAIN_APPROX_NONE
        )

        val paths = mutableListOf<Path>()

        for (i in contours.indices) {
            val contour = MatOfPoint2f()
            contour.fromList(contours[i].toList())

            val path = Path()
            val points = contour.toArray()

            path.moveTo(points[0].x.toFloat(), points[0].y.toFloat())
            for (j in 1 until points.size) {
                path.lineTo(points[j].x.toFloat(), points[j].y.toFloat())
            }

            paths.add(path)

            contour.release()
        }

        gray.release()
        binary.release()
        hierarchy.release()
        tmp.release()

        return paths
    }*/

    fun scalePath(path: Path, scaleX: Float, scaleY: Float): Path {
        val matrix = Matrix()
        matrix.setScale(scaleX, scaleY)

        val newPath = Path()
        path.transform(matrix, newPath)

        val matrixBounds = android.graphics.Matrix()
        newPath.transform(matrixBounds)
        val bounds = RectF()
        newPath.computeBounds(bounds,true)


        return newPath
    }
}


enum class Position {
    TOP, BOTTOM, LEFT, RIGHT
}

fun Path.lineTo(endPoint: PointF){
    lineTo(endPoint.x,endPoint.y)
}

fun Path.toShapeDrawable( stdWidth:Float, stdHeight:Float): ShapeDrawable {
    return ShapeDrawable(PathShape(this, stdWidth, stdHeight))
}

var Path.pathWidth
   get() = PathExt.getPathWidth(this)
   set(value) = PathExt.setPathWidth(this,value)

var Path.pathHeight
    get() = PathExt.getPathHeight(this)
    set(value) = PathExt.setPathHeight(this,value)

fun Path.resizePath(width: Float, height: Float)=PathExt.resizePath(this,width, height)

fun Path.pathRotation(path: Path, rotation: Float)=PathExt.setPathRotation(this,rotation)

fun Path.pathTranslationX(path: Path, translationX: Float)=PathExt.setPathTranslationX(this,translationX)

fun Path.pathTranslationY(path: Path, translationY: Float) =PathExt.setPathTranslationY(this,translationY)

fun Path.pathScaleX(scale: Float)=PathExt.setPathScaleX(this,scale)

fun Path.pathScaleY( scale: Float)=PathExt.setPathScaleY(this,scale)

fun Path.pathScale(scaleX: Float, scaleY: Float)=PathExt.scalePath(this,scaleX, scaleY)

fun Path.pathScale(scale: Float)=PathExt.scalePath(this,scale, scale)

fun Path.isTouched( x: Float, y: Float): Boolean = PathExt.isTouched(this,x, y)


/**
 * Transforms the morph at a given progress into a [Path].
 * It can optionally be scaled, using the origin (0,0) as pivot point.
 */
fun Morph.toAndroidPath(progress: Float, scale: Float = 1f,
                        path: android.graphics.Path = android.graphics.Path()):
        android.graphics.Path {
    var first = true
    path.rewind()
    forEachCubic(progress) { bezier ->
        if (first) {
            path.moveTo(bezier.anchor0X * scale, bezier.anchor0Y * scale)
            first = false
        }
        path.cubicTo(
            bezier.control0X * scale, bezier.control0Y * scale,
            bezier.control1X * scale, bezier.control1Y * scale,
            bezier.anchor1X * scale, bezier.anchor1Y * scale
        )
    }
    path.close()
    return path
}